﻿using System;
using System.Collections.Generic;
using System.ServiceModel;

namespace FastNet.Examples.ChatServer
{
	class Program
	{
		// Commands need to start off FastCommands.UserDefined, which is 100
		public sealed class Commands
		{
			public const Int32 UserConnected	= 101;
			public const Int32 UserDisconnected = 102;
			public const Int32 UserMessage		= 103;
		}


		static void Main( String[] args )
		{
			s_server = new FastServer<String>();

			s_server.AddEndpoint( new NetTcpBinding(), "net.tcp://0.0.0.0:1666/ChatServer" );

			// Processing events
			s_server.UnhandledException += OnUnhandledException;
			s_server.CommunicationException += OnCommunicationException;
			s_server.ProcessMessage += OnProcessMessage;
			s_server.ClientConnected += OnClientConnected;
			s_server.ClientDisconnected += OnClientDisconnected;

			s_server.Start();

			Console.WriteLine( "Chat server is running..." );
			Console.ReadLine();

			s_server.Stop( true );

			Console.WriteLine( "Chat server stopped successfully." );
		}


		// Throwing a fault exception in on connected event will close the channel
		private static void OnClientConnected( Object sender, FastServerClient<String> e )
		{
			lock ( s_nicknames )
			{
				if ( s_nicknames.Contains( e.Username ) )
				{
					throw new FaultException( "This nickname is already taken" );
				}
				else
				{
					// We can use this, to store any additional information we may want to. This is the <T> generic type in our server.
					e.User = Guid.NewGuid().ToString();

					s_nicknames.Add( e.Username );

					s_server.Broadcast( new FastMessage( Commands.UserConnected ).Add( "Nickname", e.Username ).Add( "Time", DateTime.UtcNow ) );
				}
			}
		}


		private static void OnClientDisconnected( Object sender, FastServerClient<String> e )
		{
			lock ( s_nicknames )
			{
				s_nicknames.Remove( e.Username );

				s_server.Broadcast( new FastMessage( Commands.UserDisconnected ).Add( "Nickname", e.Username ).Add( "Time", DateTime.UtcNow ) );
			}
		}


		private static void OnProcessMessage( Object sender, MessageEventArgs e )
		{
			FastServerClient<String> client = (FastServerClient<String>)sender;

			if ( e.Message.Command == Commands.UserMessage )
			{
				s_server.Broadcast( 
					new FastMessage( Commands.UserMessage )
						.Add( "Nickname", client.Username )
						.Add( "Message", e.Message.Get<String>( "Message" ) )
						.Add( "Time", DateTime.UtcNow ) );


			}
		}


		private static void OnUnhandledException( Object sender, ExceptionEventArgs<Exception> e )
		{
		}


		private static void OnCommunicationException( Object sender, ExceptionEventArgs<CommunicationException> e )
		{
		}


		private static FastServer<String>		s_server	= null;
		private static HashSet<String>			s_nicknames = new HashSet<String>();
	}
}
